package org.dreamwork.tools.network.bridge.client.fx;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import org.dreamwork.app.bootloader.ApplicationBootloader;
import org.dreamwork.app.bootloader.IBootable;
import org.dreamwork.concurrent.Looper;
import org.dreamwork.config.IConfiguration;
import org.dreamwork.network.service.ServiceFactory;
import org.dreamwork.tools.network.bridge.client.Keys;
import org.dreamwork.tools.network.bridge.client.NetworkBridgeClient;
import org.dreamwork.tools.network.bridge.client.data.Proxy;
import org.dreamwork.tools.network.bridge.client.fx.controllers.MainController2;
import org.dreamwork.tools.network.bridge.client.services.IBroadcastService;
import org.dreamwork.tools.network.bridge.client.services.IClientListener;
import org.dreamwork.tools.network.bridge.client.services.IClientMonitorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ResourceBundle;

import static org.dreamwork.tools.network.bridge.client.concurrent.Const.Action.ACT_TUNNELS;
import static org.dreamwork.tools.network.bridge.client.concurrent.Const.MessageType.*;

/**
 * Created by seth.yang on 2019/12/20
 */
@IBootable(argumentDef = "network-bridge-client.json")
public class AppMain extends Application {
    private final Logger logger = LoggerFactory.getLogger (AppMain.class);
    private static NetworkBridgeClient nbc;

    public static void main (String[] args) throws InvocationTargetException {
        ApplicationBootloader.run (AppMain.class, args);
    }

    public void start (IConfiguration conf) throws Exception {
        GuiContext.setConfiguration (conf);

        nbc = new NetworkBridgeClient (conf);
        IClientMonitorService monitor = ServiceFactory.get (IClientMonitorService.class);
        monitor.addListener (new IClientListener () {
            private final IBroadcastService service = ServiceFactory.get (IBroadcastService.class);
            @Override
            public void onConnected (String host, int port, Proxy proxy) {
                if (logger.isTraceEnabled ()) {
                    logger.trace ("proxy[{}] connected", proxy.name);
                }
                SystemNotification.notify (
                        GuiContext.getResource ("tips.tunnel.manager.connected", "name", proxy.name)
                );
                service.broadcast (ACT_TUNNELS, MT_TUNNEL_CONNECTED, proxy.id);
            }

            @Override
            public void onConnectFail (String host, int port, Proxy proxy) {
                if (logger.isTraceEnabled ()) {
                    logger.trace ("proxy[{}] connect failed", proxy.name);
                }
                SystemNotification.error (
                        GuiContext.getResource ("tips.tunnel.manager.connect.failed", "name", proxy.name)
                );
                service.broadcast (ACT_TUNNELS, MT_TUNNEL_CONN_FAILED, proxy.id);
            }

            @Override
            public void onClose (String host, int port, Proxy proxy, boolean planing) {
                if (logger.isTraceEnabled ()) {
                    logger.trace ("proxy[{}] closed", proxy.name);
                }
                SystemNotification.warn (
                        GuiContext.getResource ("tips.tunnel.manager.disconnected", "name", proxy.name)
                );
                service.broadcast (ACT_TUNNELS, MT_TUNNEL_DISCONNECTED, proxy.id);
            }
        });
        nbc.start ();

//        launchHttpd (conf);

        launch ();
    }

    @Override
    public void start (Stage stage) throws IOException {
        URL url = getClass ().getClassLoader ().getResource ("org/dreamwork/tools/network/bridge/client/fx/AppMain.class");
        if (url != null) {
            String form = url.toExternalForm ();
            GuiContext.jar = form.contains (".jar!");
        }

        GuiContext.ui = ResourceBundle.getBundle ("value.strings");
        Looper.create (Keys.UI.KEY_UI_BG_THREAD, 16);
        SystemNotification.setup ();

        ClassLoader loader = getClass ().getClassLoader ();
        URL icon = loader.getResource ("images/64x64/route.png");

        if (icon != null) {
            stage.getIcons ().addAll (new Image (icon.openStream ()));
        }

        GuiContext.setMainStage (stage);
        stage.setOnCloseRequest (e->{
            e.consume ();
            SystemNotification.notify (GuiContext.getResource ("tray.on-hide"));

            Platform.setImplicitExit (false);
            stage.close ();
        });
/*
        stage.setOnShown (e-> {
            System.out.println ("I'm shown");
            Looper.runInLoop (Keys.UI.KEY_UI_BG_THREAD, ()->{
                if (logger.isTraceEnabled ()) {
                    logger.trace ("reconnect to server ...");
                }
                nbc.start ();
            });
        });
*/

        StageManager.loadPage (
                new MainController2 (), stage,
                600, 400,
                true, false,
                "main.title"
        );
    }

/*
    private void launchHttpd (IConfiguration conf) throws Exception {
        // launch jetty server
        int port = conf.getInt (KEY_HTTPD_PORT, 50080);
        Server jetty = new Server ();
        ServerConnector connector = new ServerConnector (jetty);
        connector.setHost ("127.0.0.1");
        connector.setPort (port);
        connector.setReuseAddress (true);
        jetty.addConnector (connector);

        ResourceHandler resourceHandler = new ResourceHandler ();
        resourceHandler.setWelcomeFiles (new String[] {"index.html"});
        resourceHandler.setRedirectWelcome (true);
        resourceHandler.setDirectoriesListed (true);
        URL url = getClass ().getClassLoader ().getResource ("web-ui/");
        logger.trace ("url = {}", url);
        resourceHandler.setBaseResource (Resource.newResource (url));
        jetty.setHandler (new HandlerList (resourceHandler, new DefaultHandler ()));

        jetty.start ();
        logger.info ("jetty server listen on 127.0.0.1:{}", port);
    }
*/
}
